package com.vcc.service.impl;


import com.mybatisflex.core.paginate.Page;
import com.mybatisflex.core.query.QueryChain;
import com.mybatisflex.core.update.UpdateChain;
import com.mybatisflex.spring.service.impl.ServiceImpl;
import com.vcc.core.constant.CardStatusEnum;
import com.vcc.core.exception.NotFoundException;
import com.vcc.core.exception.ProgramException;
import com.vcc.core.util.RegexUtil;
import com.vcc.data.entity.CardType;
import com.vcc.data.mapper.CardTypeMapper;
import com.vcc.service.boss.request.card.*;
import com.vcc.service.service.CardTypeService;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.util.List;

import static com.vcc.data.entity.table.CardTypeTableDef.CARD_TYPE;

@Service
public class CardTypeServiceImpl extends ServiceImpl<CardTypeMapper, CardType> implements CardTypeService {

    @Override
    public CardType addCard(BossCardTypeCreateRequest bossCardTypeCreateRequest) {
        return null;
    }

    @Override
    public Page<CardType> paging(Page<CardType> pageable,
                                 String channelName,
                                 String sectionNo,
                                 Integer status,
                                 String secnes,
                                 String type) {
        QueryChain<CardType> queryChain = queryChain();
        if (RegexUtil.checkStringIsNotNull(sectionNo)) {
            queryChain.like(CardType::getSectionNo, sectionNo);
        }
        if (RegexUtil.checkStringIsNotNull(channelName)) {
            queryChain.eq(CardType::getChannelName, channelName);
        }
        if (RegexUtil.checkObjectIsNotNull(status)) {
            queryChain.eq(CardType::getStatus, status);
        }
        if (RegexUtil.checkObjectIsNotNull(secnes)) {
            queryChain.like(CardType::getCardScenes, secnes);
        }
        if (RegexUtil.checkStringIsNotNull(type)) {
            queryChain.like(CardType::getType, type);
        }
        queryChain.orderBy(CARD_TYPE.SORT.asc());
        return queryChain.page(pageable);
    }

    @Override
    public List<CardType> listAll(String channelName, String sectionNo) {
        QueryChain<CardType> queryChain = queryChain();
        if (RegexUtil.checkStringIsNotNull(sectionNo)) {
            queryChain.like(CardType::getSectionNo, sectionNo);
        }
        if (RegexUtil.checkStringIsNotNull(channelName)) {
            queryChain.eq(CardType::getChannelName, channelName);
        }
        queryChain.orderBy(CARD_TYPE.SORT.asc());
        return queryChain.list();
    }

    @Override
    public Page<CardType> paging(Page<CardType> pageable,
                                 String sectionNo,
                                 Integer status,
                                 String account,
                                 String secnes) {
        QueryChain<CardType> queryChain = queryChain();
        if (RegexUtil.checkStringIsNotNull(sectionNo)) {
            queryChain.eq(CardType::getSectionNo, sectionNo);
        }
        if (RegexUtil.checkObjectIsNotNull(status)) {
            queryChain.eq(CardType::getStatus, status);
        } else {
            queryChain.in(CardType::getStatus, CardStatusEnum.ACTIVE.getCode(), CardStatusEnum.INACTIVE.getCode());
        }
        if (RegexUtil.checkObjectIsNotNull(secnes)) {
            queryChain.like(CardType::getCardScenes, secnes);
        }

//        queryChain.like(CardType::getWhiteList, account).or().isNull(CardType::getWhiteList).or().eq(CardType::getWhiteList, "");
        queryChain.orderBy(CARD_TYPE.SORT.asc());

        return queryChain.page(pageable);
    }

    @Override
    public List<CardType> listBySectionNo(String sectionNo) {
        QueryChain<CardType> queryChain = queryChain();
        if (RegexUtil.checkStringIsNotNull(sectionNo)) {
            queryChain.like(CardType::getSectionNo, sectionNo);
        }
        queryChain.eq(CardType::getStatus, 0);
        queryChain.limit(20);
        return queryChain.list();
    }

    @Override
    public CardType getById(Long id) {
        return queryChain().eq(CardType::getId, id).oneOpt().orElseThrow(() -> new NotFoundException("没有当前卡信息"));
    }

    @Override
    public Boolean updateInfo(BossCardTypeUpdateRequest cardDto) {
        return update(cardDto);
    }

    @Override
    public Boolean updateInfo(BossCardTypeBatchUpdateRequest cardDto) {
        for (Long id : cardDto.getIds()) {
            BossCardTypeUpdateRequest bossCardTypeUpdateRequest = cardDto.getBossCardTypeUpdateRequest();
            bossCardTypeUpdateRequest.setId(id);
            update(bossCardTypeUpdateRequest);
        }
        return true;
    }

    private boolean update(BossCardTypeUpdateRequest cardDto) {
        if (RegexUtil.checkObjectIsNull(cardDto.getId()) || cardDto.getId() < 0) {
            throw new ProgramException("卡ID信息异常");
        }
        CardType card = getById(cardDto.getId());
        UpdateChain<CardType> updateChain = updateChain();
        if (RegexUtil.checkStringIsNotNull(cardDto.getRemark()) && !card.getRemark().equals(cardDto.getRemark())) {
            updateChain.set(CardType::getRemark, cardDto.getRemark());
        }
        if (RegexUtil.checkStringIsNotNull(cardDto.getCountry()) && !card.getCountry().equals(cardDto.getCountry())) {
            updateChain.set(CardType::getCountry, cardDto.getCountry());
        }
        if (RegexUtil.checkObjectIsNotNull(cardDto.getVerifyOpenCardStatus()) && !card.getVerifyOpenCardStatus().equals(cardDto.getVerifyOpenCardStatus())) {
            updateChain.set(CardType::getVerifyOpenCardStatus, cardDto.getVerifyOpenCardStatus());
        }
        if (RegexUtil.checkObjectIsNotNull(cardDto.getVerifyRechargeCardStatus()) && !card.getVerifyRechargeCardStatus().equals(cardDto.getVerifyRechargeCardStatus())) {
            updateChain.set(CardType::getVerifyRechargeCardStatus, cardDto.getVerifyRechargeCardStatus());
        }
        if (RegexUtil.checkObjectIsNotNull(cardDto.getVerifyOutCardStatus()) && !card.getVerifyOutCardStatus().equals(cardDto.getVerifyOutCardStatus())) {
            updateChain.set(CardType::getVerifyOutCardStatus, cardDto.getVerifyOutCardStatus());
        }
        if (RegexUtil.checkObjectIsNotNull(cardDto.getVerifyCloseCardStatus()) && !card.getVerifyOutCardStatus().equals(cardDto.getVerifyCloseCardStatus())) {
            updateChain.set(CardType::getVerifyCloseCardStatus, cardDto.getVerifyCloseCardStatus());
        }
        if (RegexUtil.checkObjectIsNotNull(cardDto.getVerifyFreezeUnFreezeCardStatus()) && !card.getVerifyFreezeUnFreezeCardStatus().equals(cardDto.getVerifyFreezeUnFreezeCardStatus())) {
            updateChain.set(CardType::getVerifyFreezeUnFreezeCardStatus, cardDto.getVerifyFreezeUnFreezeCardStatus());
        }
        if (RegexUtil.checkObjectIsNotNull(cardDto.getDealerMinAmount()) && !card.getDealerMinAmount().equals(cardDto.getDealerMinAmount())) {
            updateChain.set(CardType::getDealerMinAmount, cardDto.getDealerMinAmount());
        }
        if (RegexUtil.checkObjectIsNotNull(cardDto.getOpenCardRechargeMinAmount()) && card.getOpenCardRechargeMinAmount().compareTo(cardDto.getOpenCardRechargeMinAmount()) != 0 && cardDto.getOpenCardRechargeMinAmount().compareTo(BigDecimal.ZERO) > -1) {
            updateChain.set(CardType::getOpenCardRechargeMinAmount, cardDto.getOpenCardRechargeMinAmount());
        }
        if (RegexUtil.checkObjectIsNotNull(cardDto.getWithdrawMinAmount()) && card.getWithdrawMinAmount().compareTo(cardDto.getWithdrawMinAmount()) != 0 && cardDto.getWithdrawMinAmount().compareTo(BigDecimal.ZERO) > -1) {
            updateChain.set(CardType::getWithdrawMinAmount, cardDto.getWithdrawMinAmount());
        }
        if (RegexUtil.checkObjectIsNotNull(cardDto.getCloseCardMinAmount()) && card.getCloseCardMinAmount().compareTo(cardDto.getCloseCardMinAmount()) != 0 && cardDto.getCloseCardMinAmount().compareTo(BigDecimal.ZERO) > -1) {
            updateChain.set(CardType::getCloseCardMinAmount, cardDto.getCloseCardMinAmount());
        }
        if (RegexUtil.checkObjectIsNotNull(cardDto.getRechargeMinAmount()) && card.getRechargeMinAmount().compareTo(cardDto.getRechargeMinAmount()) != 0 && cardDto.getRechargeMinAmount().compareTo(BigDecimal.ZERO) > -1) {
            updateChain.set(CardType::getRechargeMinAmount, cardDto.getRechargeMinAmount());
        }
        if (RegexUtil.checkObjectIsNotNull(cardDto.getCloseStatus()) && !card.getCloseStatus().equals(cardDto.getCloseStatus())) {
            updateChain.set(CardType::getCloseStatus, cardDto.getCloseStatus());
        }
        if (RegexUtil.checkObjectIsNotNull(cardDto.getWithdrawStatus()) && !card.getWithdrawStatus().equals(cardDto.getWithdrawStatus())) {
            updateChain.set(CardType::getWithdrawStatus, cardDto.getWithdrawStatus());
        }
        if (RegexUtil.checkObjectIsNotNull(cardDto.getMinAuthThresholdAmount()) && card.getMinAuthThresholdAmount().compareTo(cardDto.getMinAuthThresholdAmount()) != 0 && cardDto.getMinAuthThresholdAmount().compareTo(BigDecimal.ZERO) > -1) {
            updateChain.set(CardType::getMinAuthThresholdAmount, cardDto.getMinAuthThresholdAmount());
        }
        if (RegexUtil.checkObjectIsNotNull(cardDto.getAuthFee()) && card.getAuthFee().compareTo(cardDto.getAuthFee()) != 0 && cardDto.getAuthFee().compareTo(BigDecimal.ZERO) > -1) {
            updateChain.set(CardType::getAuthFee, cardDto.getAuthFee());
        }
        if (RegexUtil.checkObjectIsNotNull(cardDto.getAuthFeeRate()) && card.getAuthFeeRate().compareTo(cardDto.getAuthFeeRate()) != 0 && cardDto.getAuthFeeRate().compareTo(BigDecimal.ZERO) > -1) {
            updateChain.set(CardType::getAuthFeeRate, cardDto.getAuthFeeRate());
        }
        if (RegexUtil.checkObjectIsNotNull(cardDto.getFailFee()) && card.getFailFee().compareTo(cardDto.getFailFee()) != 0 && cardDto.getFailFee().compareTo(BigDecimal.ZERO) > -1) {
            updateChain.set(CardType::getFailFee, cardDto.getFailFee());
        }
        if (RegexUtil.checkObjectIsNotNull(cardDto.getFailFeeRate()) && card.getFailFeeRate().compareTo(cardDto.getFailFeeRate()) != 0 && cardDto.getFailFeeRate().compareTo(BigDecimal.ZERO) > -1) {
            updateChain.set(CardType::getFailFeeRate, cardDto.getFailFeeRate());
        }
        if (RegexUtil.checkObjectIsNotNull(cardDto.getMinAuthFee()) && card.getMinAuthFee().compareTo(cardDto.getMinAuthFee()) != 0 && cardDto.getMinAuthFee().compareTo(BigDecimal.ZERO) > -1) {
            updateChain.set(CardType::getMinAuthFee, cardDto.getMinAuthFee());
        }
        if (RegexUtil.checkObjectIsNotNull(cardDto.getMinAuthFeeRate()) && card.getMinAuthFeeRate().compareTo(cardDto.getMinAuthFeeRate()) != 0 && cardDto.getMinAuthFeeRate().compareTo(BigDecimal.ZERO) > -1) {
            updateChain.set(CardType::getMinAuthFeeRate, cardDto.getMinAuthFeeRate());
        }
        if (RegexUtil.checkObjectIsNotNull(cardDto.getReversalFee()) && card.getReversalFee().compareTo(cardDto.getReversalFee()) != 0 && cardDto.getReversalFee().compareTo(BigDecimal.ZERO) > -1) {
            updateChain.set(CardType::getReversalFee, cardDto.getReversalFee());
        }
        if (RegexUtil.checkObjectIsNotNull(cardDto.getReversalFeeRate()) && card.getReversalFeeRate().compareTo(cardDto.getReversalFeeRate()) != 0 && cardDto.getReversalFeeRate().compareTo(BigDecimal.ZERO) > -1) {
            updateChain.set(CardType::getReversalFeeRate, cardDto.getReversalFeeRate());
        }
        if (RegexUtil.checkObjectIsNotNull(cardDto.getRefundFee()) && card.getRefundFee().compareTo(cardDto.getRefundFee()) != 0 && cardDto.getRefundFee().compareTo(BigDecimal.ZERO) > -1) {
            updateChain.set(CardType::getRefundFee, cardDto.getRefundFee());
        }
        if (RegexUtil.checkObjectIsNotNull(cardDto.getRefundFeeRate()) && card.getRefundFeeRate().compareTo(cardDto.getRefundFeeRate()) != 0 && cardDto.getRefundFeeRate().compareTo(BigDecimal.ZERO) > -1) {
            updateChain.set(CardType::getRefundFeeRate, cardDto.getRefundFeeRate());
        }
        if (RegexUtil.checkObjectIsNotNull(cardDto.getCrossBorderFee()) && card.getCrossBorderFee().compareTo(cardDto.getCrossBorderFee()) != 0 && cardDto.getCrossBorderFee().compareTo(BigDecimal.ZERO) > -1) {
            updateChain.set(CardType::getCrossBorderFee, cardDto.getCrossBorderFee());
        }
        if (RegexUtil.checkObjectIsNotNull(cardDto.getCrossBorderFeeRate()) && card.getCrossBorderFeeRate().compareTo(cardDto.getCrossBorderFeeRate()) != 0 && cardDto.getCrossBorderFeeRate().compareTo(BigDecimal.ZERO) > -1) {
            updateChain.set(CardType::getCrossBorderFeeRate, cardDto.getCrossBorderFeeRate());
        }
        if (RegexUtil.checkObjectIsNotNull(cardDto.getCardScenes()) && !cardDto.getCardScenes().equals(card.getCardScenes())) {
            updateChain.set(CardType::getCardScenes, cardDto.getCardScenes());
        }
        if (RegexUtil.checkObjectIsNotNull(cardDto.getType()) && !cardDto.getType().equals(card.getType())) {
            updateChain.set(CardType::getType, cardDto.getType());
        }
        updateChain.eq(CardType::getId, card.getId());
        return updateChain.update();
    }

    @Override
    public CardType addCardType(BossCardTypeCreateRequest bossCardTypeCreateRequest) {
        CardType card = new CardType();
        card.setSectionNo(bossCardTypeCreateRequest.getSectionNo());
        card.setCode(bossCardTypeCreateRequest.getCode());
        card.setCurrencyCode(bossCardTypeCreateRequest.getCurrencyCode());
        card.setCurrencyName(bossCardTypeCreateRequest.getCurrencyName());
        card.setRemark(bossCardTypeCreateRequest.getRemark());
        card.setVerifyOpenCardStatus(bossCardTypeCreateRequest.getVerifyOpenCardStatus());
        card.setVerifyRechargeCardStatus(bossCardTypeCreateRequest.getVerifyRechargeCardStatus());
        card.setVerifyOutCardStatus(bossCardTypeCreateRequest.getVerifyOutCardStatus());
        card.setVerifyCloseCardStatus(bossCardTypeCreateRequest.getVerifyCloseCardStatus());
        card.setVerifyFreezeUnFreezeCardStatus(bossCardTypeCreateRequest.getVerifyFreezeUnFreezeCardStatus());
        card.setCardLabel(bossCardTypeCreateRequest.getCardLabel());
        card.setChannelName(bossCardTypeCreateRequest.getChannelName());
        card.setStatus(0);
        card.setCountry(bossCardTypeCreateRequest.getCountry());
        card.setVerifySpecialStatus(0);
        card.setSort(0);
        card.setInitAmount(BigDecimal.ZERO);
        card.setDealerMinAmount(bossCardTypeCreateRequest.getDealerMinAmount());
        card.setOpenCardRechargeMinAmount(BigDecimal.valueOf(1));
        card.setWithdrawMinAmount(BigDecimal.ZERO);
        card.setRechargeMinAmount(BigDecimal.ONE);
        card.setCloseCardMinAmount(BigDecimal.ZERO);
        card.setWithdrawStatus(CardStatusEnum.ACTIVE.getCode());
        card.setCloseStatus(CardStatusEnum.ACTIVE.getCode());
        card.setMinAuthThresholdAmount(bossCardTypeCreateRequest.getMinAuthThresholdAmount());
        card.setAuthFee(bossCardTypeCreateRequest.getAuthFee());
        card.setAuthFeeRate(bossCardTypeCreateRequest.getAuthFeeRate());
        card.setFailFee(bossCardTypeCreateRequest.getFailFee());
        card.setFailFeeRate(bossCardTypeCreateRequest.getFailFeeRate());
        card.setMinAuthFee(bossCardTypeCreateRequest.getMinAuthFee());
        card.setMinAuthFeeRate(bossCardTypeCreateRequest.getMinAuthFeeRate());
        card.setReversalFee(bossCardTypeCreateRequest.getReversalFee());
        card.setReversalFeeRate(bossCardTypeCreateRequest.getReversalFeeRate());
        card.setRefundFee(bossCardTypeCreateRequest.getRefundFee());
        card.setRefundFeeRate(bossCardTypeCreateRequest.getRefundFeeRate());
        card.setCrossBorderFee(bossCardTypeCreateRequest.getCrossBorderFee());
        card.setCrossBorderFeeRate(bossCardTypeCreateRequest.getCrossBorderFeeRate());
        card.setCardScenes(bossCardTypeCreateRequest.getCardScenes());
        card.setType(bossCardTypeCreateRequest.getType());
        save(card);
        return card;
    }

    @Override
    public CardType getBySectionNo(String sectionNo) {
        return queryChain().eq(CardType::getSectionNo, sectionNo).oneOpt().orElseThrow(() -> new NotFoundException("没有此卡种"));
    }

    @Override
    public List<CardType> listByChannelName(String channelName) {
        return queryChain().eq(CardType::getChannelName, channelName).list();
    }

    @Override
    public List<CardType> listByChannelNameAndType(String channelName, String type) {
        QueryChain<CardType> queryChain = queryChain();
        if (RegexUtil.checkStringIsNotNull(channelName)) {
            queryChain.eq(CardType::getChannelName, channelName);
        }
        if (RegexUtil.checkStringIsNotNull(type)) {
            queryChain.eq(CardType::getType, type);
        }
        return queryChain.list();
    }

    @Override
    public Boolean updateStatus(BossCardTypeStatusUpdateRequest updateCardStatusDto, Long userId) {
        CardType card = getById(updateCardStatusDto.getId());
        if (card.getStatus().equals(updateCardStatusDto.getStatus())) {
            throw new ProgramException("状态一致无需变更");
        }
        return updateChain().eq(CardType::getStatus, card.getStatus()).eq(CardType::getId, card.getId()).set(CardType::getOperationUserId, userId).set(CardType::getStatus, updateCardStatusDto.getStatus()).update();
    }

    @Override
    public Boolean updateAdminRemark(BossCardTypeRemarkUpdateRequest bossCardTypeRemarkUpdateRequest, Long userId) {
        CardType card = getById(bossCardTypeRemarkUpdateRequest.getId());
        return updateChain()
                .eq(CardType::getId, card.getId())
                .set(CardType::getOperationUserId, userId)
                .set(CardType::getAdminRemark, bossCardTypeRemarkUpdateRequest.getRemark())
                .update();
    }

    @Override
    public Boolean updateSort(BossCardTypeSortUpdateRequest bossCardTypeSortUpdateRequest, Long userId) {
        CardType card = getById(bossCardTypeSortUpdateRequest.getId());
        if (card.getSort().equals(bossCardTypeSortUpdateRequest.getSort())) {
            throw new ProgramException("排序一致无需变更");
        }
        return updateChain().eq(CardType::getId, card.getId()).set(CardType::getOperationUserId, userId).set(CardType::getSort, bossCardTypeSortUpdateRequest.getSort()).update();
    }

    @Override
    public Boolean updateSort(BossCardTypeSortBatchUpdateRequest updateCardSortDto, Long userId) {
        return updateChain().in(CardType::getId, updateCardSortDto.getIds()).set(CardType::getOperationUserId, userId).set(CardType::getSort, updateCardSortDto.getStatus() ? 0 : 9999).update();

    }

    @Override
    public List<CardType> listByStatus(Integer status) {
        return queryChain().eq(CardType::getStatus, status).list();
    }

    @Override
    public List<CardType> listBySectionNoAndStatus(String sectionNo, Integer status) {
        return queryChain().like(CardType::getSectionNo, sectionNo).eq(CardType::getStatus, status).list();
    }

    @Override
    public List<CardType> listBySectionNoAndStatus(String sectionNo, String channelCode, Integer status) {
        QueryChain<CardType> cardTypeQueryChain = queryChain();
        cardTypeQueryChain.where(CARD_TYPE.SECTION_NO.like(sectionNo, StringUtils::isNotBlank));
        cardTypeQueryChain.where(CARD_TYPE.CHANNEL_NAME.eq(channelCode, StringUtils::isNotBlank));
        cardTypeQueryChain.where(CARD_TYPE.STATUS.eq(status, status != null));
        cardTypeQueryChain.orderBy(CARD_TYPE.SORT.asc());
        return cardTypeQueryChain.list();
    }
}
